#pragma once
#include "util.h"
#include <cpr/response.h>
#include <elasticlient/client.h>

namespace biteics {
	//核心基类（Base）
	//所有数据结构类的父类，提供基础的数据存储和序列化能力
	class Base {
	public:
		using ptr = std::shared_ptr<Base>;
		Base(const std::string &key);// 构造函数：接收一个"键名"（用于标识当前对象的JSON键）
		

		template<typename T>
		void add(const std::string& key, const T &val) {
			_val[key] = val;
		}
		// 模板方法：向内部JSON对象的数组字段追加数据（如给skills数组添加新技能）
		template<typename T>
		void append(const std::string& key, const T &val) {
			_val[key].append(val);//追加元素到数组
		}

		const std::string& key() const;  //  getter方法：获取当前对象的键名（_key）
    	virtual const Json::Value val() const;  // 虚方法：返回当前对象对应的JSON结构
    	virtual std::string to_string() const;  // 虚方法：将JSON结构序列化为字符串

	protected:
		std::string _key;// 存储当前对象的JSON键名（如"settings"、"mappings"）
		Json::Value _val;// 核心存储：JSON对象，用于保存所有数据（最终序列化给ES）


	};
	//复合数据结构类（Object/Array）
	//“对象”（键值对集合）和 “数组”（有序元素集合）,用于构建嵌套的 JSON 结构
	class Array;// 前向声明：因为Object中要用到Array的智能指针，需提前声明
	class Object : public Base {
		public:
			using ptr = std::shared_ptr<Object>;
			Object(const std::string &key);//接收JSON键名（如"analyzer"）

			// 模板方法：根据键名获取子元素（如从_subs中获取key为"ikmax"的Tokenizer对象）
			template<typename R>
			std::shared_ptr<R> getElement(const std::string &key) {
				auto it = _subs.find(key);
				if(it == _subs.end()) {
					return nullptr;
				}
				// 类型转换为目标子类指针
				return std::dynamic_pointer_cast<R>(it->second);
			}

			// 创建一个子Object对象并添加到_subs
			std::shared_ptr<Object> newObject(const std::string &key);
			// 创建一个子Array对象并添加到_subs
    		std::shared_ptr<Array> newArray(const std::string &key);
    		void addElement(const Base::ptr &sub);  // 直接添加一个Base子类对象到_subs

    		virtual const Json::Value val() const;
    		virtual std::string to_string() const;
		
		protected:
			// 存储子元素：键为子元素的名称（如"ikmax"），值为子元素的智能指针（Base子类）
			std::unordered_map<std::string, Base::ptr> _subs;
	};

	//Array类（对应 JSON 数组）
	class Array: public Base {
        public:
            using ptr = std::shared_ptr<Array>;
            Array(const std::string &key);
            std::shared_ptr<Object> newObject(const std::string &key);
            std::shared_ptr<Array> newArray(const std::string &key);
            void addElement(const Base::ptr &sub);
            virtual const Json::Value val() const;
            virtual std::string to_string() const;
        private:
            std::vector<Base::ptr> _subs;
    };

	//Elasticsearch 索引配置类
	//专门用于构建 Elasticsearch 索引的 settings（配置）和 mappings（映射），
	//对应 ES 索引创建时的核心参数
	
	// 分词器配置类（对应ES的"tokenizer"）
	class Tokenizer : public Object{
	public:
	    using ptr = std::shared_ptr<Tokenizer>;
	    Tokenizer(const std::string &str);  // 构造函数：接收分词器名称（如"ik_max_word"）
	    void tokenizer(const std::string &t);  // 设置分词器类型（如"ik_max_word"）
	    void type(const std::string &type);  // 设置分词器的类型（如"custom"）
	};

	// 分析器配置类（对应ES的"analyzer"）
	class Analyzer : public Object {
	public:
	    using ptr = std::shared_ptr<Analyzer>;
	    Analyzer();  // 构造函数：初始化analyzer对应的JSON结构
	    Tokenizer::ptr tokenizer(const std::string &tokenizer_name);  // 为分析器添加分词器
	};

	// 分析配置总类（对应ES的"analysis"）
	class Analysis : public Object {
	public:
	    using ptr = std::shared_ptr<Analysis>;
	    Analysis();  // 构造函数：初始化analysis对应的JSON结构
	    Analyzer::ptr analyzer();  // 创建并返回一个Analyzer子对象
	};

	//索引配置类
	class Settings : public Object {
	public:
	    using ptr = std::shared_ptr<Settings>;
	    Settings();  // 构造函数：初始化settings对应的JSON结构（如"analysis"节点）
	    Analysis::ptr analysis();  // 创建并返回Analysis子对象（用于配置分词器）
	};

	// 字段配置类（对应ES mappings中的单个字段，如"name"、"age"）
	class Field : public Object {
	public:
	    using ptr = std::shared_ptr<Field>;
	    Field(const std::string &key);  // 构造函数：接收字段名（如"name"）
	    void type(const std::string &type);  // 设置字段类型（如"text"、"keyword"）
	    void boost(double boost);  // 设置字段权重（如3.0）
	    void index(bool flag);  // 设置字段是否创建索引（true/false）
	    void analyzer(const std::string &analizer_name);  // 设置字段使用的分词器（如"ikmax"）
	};

	// 字段集合类（对应ES mappings中的"properties"）
	class Properties : public Object {
	public:
	    using ptr = std::shared_ptr<Properties>;
	    Properties();  // 构造函数：初始化properties对应的JSON结构
	    Field::ptr field(const std::string &field_name);  // 创建并返回一个Field子对象（添加字段）
	};

	// 映射总类（对应ES的"mapping"）
	class Mappings : public Object {
	public:
	    using ptr = std::shared_ptr<Mappings>;
	    Mappings();  // 构造函数：初始化mapping对应的JSON结构
	    Properties::ptr properties();  // 创建并返回Properties子对象（用于添加字段）
	    void dynamic(bool flag);  // 设置dynamic参数（true/false，是否自动添加字段）
	};

	//基础查询条件类
	// Term查询（精确匹配，对应ES的"term"）
	class Term : public Object {
	public:
	    using ptr = std::shared_ptr<Term>;
	    Term(const std::string &field);  // 构造函数：接收字段名（如"phone"）
	    template<typename T>
	    void setValue(const T &value) {  // 设置匹配值（如"13888888888"）
	        this->add(_field, value);  // 向JSON中添加"字段名: 值"的键值对
	    }
	private:
	    std::string _field;  // 存储查询的字段名
	};

	// Terms查询（多值精确匹配，对应ES的"terms"）
	class Terms : public Object {
	public:
	    using ptr = std::shared_ptr<Terms>;
	    Terms(const std::string &field);  // 构造函数：接收字段名（如"skills"）
	    template<typename T>
	    void setValue(const T &value) {  // 向字段中追加匹配值（如"java"、"go"）
	        this->append(_field, value);  // 追加到数组（对应terms的多值）
	    }
	private:
	    std::string _field;
	};

	// Match查询（全文检索，对应ES的"match"）
	class Match : public Object {
	public:
	    using ptr = std::shared_ptr<Match>;
	    Match(const std::string &field);  // 构造函数：接收字段名（如"name"）
	    template<typename T>
	    void setValue(const T &value) {  // 设置检索关键词（如"张三"）
	        this->add(_field, value);
	    }
	private:
	    std::string _field;
	};

	// MultiMatch查询（多字段全文检索，对应ES的"multi_match"）
	class MultiMatch : public Object {
	public:
	    using ptr = std::shared_ptr<MultiMatch>;
	    MultiMatch();  // 构造函数：初始化multi_match结构
	    void appendField(const std::string &field);//添加检索字段（如同时检索"name"和"skills"）
	    template<typename T>
	    void setQuery(const T &query) {  // 设置检索关键词（如"java"）
	        this->add("query", query);
	    }
	};

	// Range查询（范围查询，对应ES的"range"）
	class Range : public Object {
	public:
	    using ptr = std::shared_ptr<Range>;
	    Range(const std::string &field);  // 构造函数：接收字段名（如"age"）
	    template<typename T>
	    void setRange(const T &gt, const T& lt) {  // 设置范围（gt=大于，lt=小于）
	        _sub->add("gt", gt);  // 如age > 18
	        _sub->add("lt", lt);  // 如age < 30
	    }
	private:
	    Object::ptr _sub;  // 存储range的子条件（gt/lt/gte/lte）
	};

	//Bool 查询相关类
	// 查询对象基类（用于承载bool查询的子条件）
	class QObject : public Object {
	public:
	    using ptr = std::shared_ptr<QObject>;
	    QObject(const std::string &key);  // 构造函数：接收查询类型键名（如"bool"）
	    Term::ptr term(const std::string &field);  // 创建Term查询子对象
	    Terms::ptr terms(const std::string &field);  // 创建Terms查询子对象
	    Match::ptr match(const std::string &field);  // 创建Match查询子对象
	    MultiMatch::ptr multi_match();  // 创建MultiMatch查询子对象
	    Range::ptr range(const std::string &field);  // 创建Range查询子对象
	};

	// 查询数组基类（对应bool查询中的数组条件，如"must"数组）
	class QArray : public Array {
	public:
	    using ptr = std::shared_ptr<QArray>;
	    QArray(const std::string &key);  // 构造函数：接收数组键名（如"must"）
	    // 以下方法与QObject一致，用于在数组中添加查询条件
	    Term::ptr term(const std::string &field);
	    Terms::ptr terms(const std::string &field);
	    Match::ptr match(const std::string &field);
	    MultiMatch::ptr multi_match(); 
	    Range::ptr range(const std::string &field);
	};

	// Bool查询的"must"条件（必须满足，对应ES的"must"）
	class Must : public QArray {
	public:
	    using ptr = std::shared_ptr<Must>;
	    Must();  // 构造函数：键名为"must"
	};

	// Bool查询的"should"条件（可选满足，对应ES的"should"）
	class Should : public QArray {
	public:
	    using ptr = std::shared_ptr<Should>;
	    Should();  // 构造函数：键名为"should"
	};

	// Bool查询的"must_not"条件（必须不满足，对应ES的"must_not"）
	class MustNot : public QArray {
	public:
	    using ptr = std::shared_ptr<MustNot>;
	    MustNot();  // 构造函数：键名为"must_not"
	};

	// Bool查询总类（对应ES的"bool"查询）
	class QBool : public QObject {
	public:
	    using ptr = std::shared_ptr<QBool>;
	    QBool();  // 构造函数：键名为"bool"
	    Must::ptr must();  // 创建must子条件数组
	    Should::ptr should();  // 创建should子条件数组
	    MustNot::ptr must_not();  // 创建must_not子条件数组
	    void minimum_should_match(size_t count);  // 设置should的最小匹配数（如1）
	};

	//查询总类
	class Query : public QObject {
	public:
	    using ptr = std::shared_ptr<Query>;
	    Query();  // 构造函数：键名为"query"（ES查询DSL的根节点）
	    void match_all();  // 添加match_all查询（匹配所有文档）
	    QBool::ptr qbool();  // 创建bool查询子对象
	    // 快捷方法：直接创建must/should/must_not条件（无需先获取qbool）
	    Must::ptr must();
	    Should::ptr should();
	    MustNot::ptr must_not();
	};

	//请求参数类（Request及子类）

	//基础请求类
	class Request {
	public:
	    // 构造函数：初始化索引名、类型、操作类型、文档ID
	    Request(const std::string &index, const std::string &type, 
			const std::string &op, const std::string &id);
	    // setter方法：修改索引名、类型、操作类型、文档ID
	    void set_index(const std::string &index);
	    void set_type(const std::string &type);
	    void set_op(const std::string &op);
	    void set_id(const std::string &id);
	    // getter方法：获取上述参数
	    const std::string& index() const;
	    const std::string& type() const;
	    const std::string& op() const;
	    const std::string& id() const;
	protected:
	    std::string _index;  // 索引名（如"student"）
	    std::string _type;   // 文档类型（ES 7.x后默认"_doc"）
	    std::string _op;     // 操作类型（如"create"、"insert"、"update"）
	    std::string _id;     // 文档ID（如"2"）
	};

	// 索引创建请求类（对应ES创建索引操作）
	class Indexer : public Object, public Request {
	public:
	    using ptr = std::shared_ptr<Indexer>;
	    Indexer(const std::string &index);  // 构造函数：接收索引名
	    Settings::ptr settings();  // 创建settings子对象（配置索引）
	    Tokenizer::ptr tokenizer(const std::string &tokenizer_name);  // 快捷创建分词器
	    Mappings::ptr mappings();  // 创建mappings子对象（配置字段）
	    Field::ptr field(const std::string &field_name);  // 快捷创建字段映射
	};

	// 数据插入请求类（对应ES新增文档操作）
	class Inserter : public Object, public Request {
	public:
	    using ptr = std::shared_ptr<Inserter>;
	    // 构造函数：接收索引名和文档ID（新增文档的ID）
	    Inserter(const std::string &index, const std::string &id);
	};

	// 数据更新请求类（对应ES更新文档操作）
	class Updater : public Object, public Request {
	public:
	    using ptr = std::shared_ptr<Updater>;
	    // 构造函数：接收索引名和文档ID（要更新的文档ID）
	    Updater(const std::string &index, const std::string &id);
	    Object::ptr doc();  // 创建"doc"子对象（ES更新操作需包裹在doc中）
	    // 模板方法：向更新文档中添加字段（调用doc()->add）
	    template<typename T>
	    void add(const std::string &key, const T &val) {
	        this->doc()->add(key, val);
	    }
	    // 模板方法：向更新文档的数组字段追加数据
	    template<typename T>
	    void append(const std::string &key, const T &val) {
	        this->doc()->append(key, val);
	    }
	};

	// 数据删除请求类（对应ES删除文档操作）
	class Deleter : public Object, public Request {
	public:
	    using ptr = std::shared_ptr<Deleter>;
	    // 构造函数：接收索引名和文档ID（要删除的文档ID）
	    Deleter(const std::string &index, const std::string &id);
	};

	// 数据查询请求类（对应ES搜索操作）
	class Searcher : public Object, public Request  {
	public:
	    Searcher(const std::string &index);  // 构造函数：接收索引名
	    Query::ptr query();  // 创建查询条件子对象（配置DSL）
	    void size(size_t count);  // 设置返回结果数量（如10）
	    void from(size_t offset);  // 设置结果偏移量（用于分页，如从第0条开始）
	};

	//客户端接口类
	class BaseClient {
	public:
	    using ptr = std::shared_ptr<BaseClient>;
	    BaseClient() = default;  // 默认构造函数
	    virtual ~BaseClient() = default;  // 虚析构函数：确保子类正确析构

	    // 纯虚方法：定义客户端必须实现的操作（子类需重写）
	    virtual bool create(const Indexer &idx) = 0;  // 创建索引
	    virtual bool insert(const Inserter &ins) = 0;  // 插入文档
	    virtual bool update(const Updater &upd) = 0;  // 更新文档
	    virtual bool remove(const Deleter &del) = 0;  // 删除文档
	    virtual bool remove(const std::string &index) = 0;  // 删除索引
	    // 搜索文档：返回optional<Json::Value>，空表示查询失败
	    virtual std::optional<Json::Value> search(const Searcher &sea) = 0;
	};

	//客户端实现类
	class ESClient : public BaseClient {
	public:
	    using ptr = std::shared_ptr<ESClient>;
	    // 构造函数：接收ES服务器地址列表（如{"http://192.168.8.128:9200/"}）
	    ESClient(const std::vector<std::string> &hosts);

	    // 重写BaseClient的纯虚方法（实现具体的ES交互逻辑）
	    bool create(const Indexer &idx) override;
	    bool insert(const Inserter &ins) override;
	    bool update(const Updater &upd) override;
	    bool remove(const Deleter &del) override;
	    bool remove(const std::string &index) override;
	    std::optional<Json::Value> search(const Searcher &sea) override;

	private:
	    // 底层ES客户端：通过elasticlient::Client实现HTTP请求发送
	    std::shared_ptr<elasticlient::Client> _client;
	};
}

